//@author A0097013L
package gui;

import java.awt.EventQueue;

import javax.swing.Action;
import javax.swing.BoundedRangeModel;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.JTextArea;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JScrollPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Toolkit;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;

import javax.swing.JPanel;

import java.awt.Dimension;

import javax.swing.border.TitledBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.JButton;
import javax.swing.SwingConstants;

import java.awt.Color;

import javax.swing.JTextPane;

import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import logger.Logger;
import logic.Mark;
import logic.Time;
import memory.GenericEvents;
import memory.Memory;

public class GuiMain implements ActionListener, DocumentListener{

	private static final String OVER = "over";
	private static final String ONGOING = "ongoing";
	private static final String UPCOMING = "upcoming";
	private static final String OVERDUE = "overdue";
	private static final String COMPLETED = "completed";
	private static final String INCOMPLETE = "incomplete";
	private JFrame frmSwing;
	private JTextField textField;
	public static JTextArea mainViewTextArea;

	private final static String newline = "\n";
	private JScrollPane mainViewScrollPane;
	
	public static List<String> words;
	private static final String COMMIT_ACTION = "commit";
    private static enum Mode { INSERT, COMPLETION };
    private Mode mode = Mode.INSERT;
    
    public static Memory mem;
    private JPanel bottomRightPanel;
    private JPanel bottomPanel;
    private JPanel bottomLeftPanel;
    
	private static final String TASK = "Task";
	private static final String DEADLINE = "Deadline";
	private static final String EVENT = "Event";
	private static final String ADD = "add";
	private static final String DELETE = "delete";
	private static final String SEARCH = "search";
	private static final String UPDATE = "update";
	private static final String DISPLAY = "display";
	private static final String UNDO = "undo";
	private static final String REDO = "redo";
	private static final String EXIT = "exit";
	private static final String CLEARSCREEN = "clear screen";
	private static final String NAME = "name";
	private static final String DESCRIPTION = "description";
	private static final String TIME = "time";
	private static final String DATE = "date";
	private static final String STARTTIME = "starttime";
	private static final String ENDTIME = "endtime";
	private static final String STARTDATE = "startdate";
	private static final String ENDDATE = "enddate";
	private static final String MARK = "mark";
	private static final String STATUS = "status";
	private static final String LEFT = "left";
	private static final String RIGHT = "right";
	private static final String UP = "up";
	private static final String DOWN = "down";
	private static final String REGULAR = "regular";
	private static final String SANSSERIF = "SansSerif";
	private static final String ITALIC = "italic";
	private static final String BOLD = "bold";
	private static final String SMALL = "small";
	private static final String LARGE = "large";
	private static final String REDLARGE = "red large";
	private static final String RED = "red";
	private static final String GREENLARGE = "green large";
	private static final String GREEN = "green";
	private static final String SIMPLY = "SIMPLY";
	private static final String HELP = "help";
	private static final String CLEAR = "clear";
	private static final String OPENBRACKETWITHSPACE = " (";
	private static final String CLOSEBRACKET = ")";
	private static final String F1 = "F1";
	private static final String F2 = "F2";
	private static final String F3 = "F3";
	private static final String F4 = "F4";
	private static final String F5 = "F5";
	private static final String ESCAPE = "ESCAPE";
	public static final String SPACE = " ";
	private static final String DASH = " - ";
	
	private JPanel taskPanel;
	private JPanel deadlinePanel;
	private JPanel eventPanel;
	private JPanel mainViewPanel;
	private JPanel buttonPanel;
	private JPanel topPanel;
	
	private JButton clearScreenButton;
	private JButton helpButton;
	private JButton displayButton;
	private JButton deleteButton;
	
	private JButton addButton;
	static JTextPane eventTextPane;
	private JScrollPane eventScrollPane;
	static JTextPane deadlineTextPane;
	private JScrollPane deadlineScrollPane;
	static JTextPane taskTextPane;
	private JScrollPane taskscrollPane;
    
	public static ObserverList observerList;
	public static StyledDocument eventStyledDoc;
	public static StyledDocument deadlineStyledDoc;
	public static StyledDocument taskStyledDoc;
	
	ClassLoader classloader = this.getClass().getClassLoader();
    PrintStream printStream;
	
	//Launch the application
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				
				try {
					//set look & feel
					try {
					    UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
					} catch (Exception e) {
					    e.printStackTrace();
					}
					
					GuiMain window = new GuiMain();	
					window.frmSwing.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	//constructor
	public GuiMain() throws IOException {
		initialize();
		setEnvironment();
      	printWelcomeMessage();
	}

	private void setEnvironment() {
        redirectSystemOut();
        
		Memory memory = initializeMemory();
		Logger.readFromFile();
		bindingEnterKey();

		addWords(memory);    
       
        setObserverList();
        
        setQuickView();
        
        addStylesToDocument(eventStyledDoc);
			
		updateQuickView();
		
        Time.initTimer(mem);
	}

	private void setQuickView() {
		eventStyledDoc = eventTextPane.getStyledDocument();
		deadlineStyledDoc = deadlineTextPane.getStyledDocument();
		taskStyledDoc = taskTextPane.getStyledDocument();
	}

	private void setObserverList() {
		observerList = new ObserverList();
	}

	private void redirectSystemOut() {
		printStream = new PrintStream(new CustomOutputStream(mainViewTextArea));
        System.setOut(printStream);
	}

	private Memory initializeMemory() {
		Memory memory = new Memory();
        mem = memory;
        memory.loadFromFile(memory);
		return memory;
	}

	private void bindingEnterKey() {
		InputMap im = textField.getInputMap();
        ActionMap am = textField.getActionMap();
        im.put(KeyStroke.getKeyStroke("ENTER"), COMMIT_ACTION);
        am.put(COMMIT_ACTION, new CommitAction());
	}
	
	protected void addStylesToDocument(StyledDocument doc) {
        //Initialize styles.
        Style def = StyleContext.getDefaultStyleContext().
                        getStyle(StyleContext.DEFAULT_STYLE);
 
        Style regular = doc.addStyle(REGULAR, def);
        StyleConstants.setFontFamily(def, SANSSERIF);
 
        Style s = doc.addStyle(ITALIC, regular);
        StyleConstants.setItalic(s, true);
 
        s = doc.addStyle(BOLD, regular);
        StyleConstants.setBold(s, true);
 
        s = doc.addStyle(SMALL, regular);
        StyleConstants.setFontSize(s, 10);
 
        s = doc.addStyle(LARGE, regular);
        StyleConstants.setFontSize(s, 18);
        StyleConstants.setBold(s, true);
        
        s = doc.addStyle(REDLARGE, regular);
        StyleConstants.setFontSize(s, 18);
        StyleConstants.setForeground(s, Color.RED);
        StyleConstants.setBold(s, true);
        
        s = doc.addStyle(RED, regular);
        StyleConstants.setForeground(s, Color.RED);

        s = doc.addStyle(GREENLARGE, regular);
        StyleConstants.setFontSize(s, 18);
        StyleConstants.setForeground(s, Color.GREEN);
        StyleConstants.setBold(s, true);
        
        s = doc.addStyle(GREEN, regular);
        StyleConstants.setForeground(s, Color.GREEN);
    }

	private void printWelcomeMessage() throws IOException {
		Main.printWelcomeMessage();
		mainViewTextArea.setCaretPosition(0);
	}
	
	private void addWords(Memory memory) {
		words = new ArrayList<String>();
		
        words.add(ADD);
        words.add(DELETE);
        words.add(SEARCH);
        words.add(UPDATE);
        words.add(DISPLAY);
        words.add(UNDO);
        words.add(REDO);
        words.add(EXIT);
        words.add(CLEARSCREEN);
        words.add(NAME);
        words.add(DESCRIPTION);
        words.add(TIME);
        words.add(DATE);
        words.add(STARTTIME);
        words.add(ENDTIME);
        words.add(STARTDATE);
        words.add(ENDDATE);
        words.add(MARK);
        words.add(STATUS);
        words.add(INCOMPLETE);
        words.add(COMPLETED);
        words.add(OVERDUE);
        words.add(UPCOMING);
        words.add(ONGOING);
        words.add(OVER);
        
        for(int i=0; i<memory.getSize(); i++) {
        	words.add(memory.get(i).getName());
        }
        
        Collections.sort(words);  
	}


	private void initialize() {
		setWindow();
		setContentPage();
	
		//hotkey area
		createTopPanel();
		createButtonsPanel();
		createHelpButton();
		createDisplayButton();
		createDeleteButton();
		createClearScreenButton();
		createAddButton();

		createMainUserInterfacePane();
		
		//quick view area
		creatQuickViewPanel();
		createEventPane();
		createDeadlinePane();
		createTaskPane();
		
		//main view & text field area
		createViewAndTextPanel();
		creatMainViewPane();
		createTextField();
		
		//other initialization
		implementUndoRedoInTextField();
		setTextCursorInTextField();
		implementHotKeys();
	}

	private void setWindow() {
		frmSwing = new JFrame();
		frmSwing.setIconImage(Toolkit.getDefaultToolkit().getImage(classloader.getResource("images/windowIcon.png")));
		frmSwing.setTitle(SIMPLY);
		frmSwing.getContentPane().setBackground(UIManager.getColor("Button.background"));
		frmSwing.setBounds(100, 50, 764, 657);
		frmSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	private void setContentPage() {
		GridBagLayout gridBagLayout = new GridBagLayout();
		gridBagLayout.rowWeights = new double[]{0.0, 1.0};
		gridBagLayout.columnWidths = new int[]{490};
		gridBagLayout.columnWeights = new double[]{1.0};
		gridBagLayout.rowHeights = new int[]{75, 580};
		frmSwing.getContentPane().setLayout(gridBagLayout);
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
	}

	private void createTopPanel() {
		topPanel = new JPanel();
		topPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GridBagConstraints gbc_topPanel = new GridBagConstraints();
		gbc_topPanel.fill = GridBagConstraints.BOTH;
		gbc_topPanel.insets = new Insets(0, 0, 5, 0);
		gbc_topPanel.gridx = 0;
		gbc_topPanel.gridy = 0;
		frmSwing.getContentPane().add(topPanel, gbc_topPanel);
		GridBagLayout gbl_topPanel = new GridBagLayout();
		gbl_topPanel.columnWidths = new int[]{490, 0};
		gbl_topPanel.rowHeights = new int[]{70, 0};
		gbl_topPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_topPanel.rowWeights = new double[]{0.0, Double.MIN_VALUE};
		topPanel.setLayout(gbl_topPanel);
	}

	private void createButtonsPanel() {
		buttonPanel = new JPanel();
		GridBagConstraints gbc_buttonPanel = new GridBagConstraints();
		gbc_buttonPanel.fill = GridBagConstraints.BOTH;
		gbc_buttonPanel.gridx = 0;
		gbc_buttonPanel.gridy = 0;
		topPanel.add(buttonPanel, gbc_buttonPanel);
		GridBagLayout gbl_buttonPanel = new GridBagLayout();
		gbl_buttonPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		gbl_buttonPanel.rowHeights = new int[]{61, 0};
		gbl_buttonPanel.columnWeights = new double[]{1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, Double.MIN_VALUE};
		gbl_buttonPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		buttonPanel.setLayout(gbl_buttonPanel);
	}

	private void createAddButton() {
		addButton = new JButton(new ImageIcon(classloader.getResource("images/add.png")));
		addButton.setFocusable(false);
		addButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (textField.getText().equals("")) {
					textField.requestFocus();
					textField.setText(ADD + SPACE);
				} else {
					String text = ADD + SPACE + textField.getText();
					Main.runCommands(text, mem);
					textField.requestFocus();	
					textField.setText("");
				}
			}
		});
		
		GridBagConstraints gbc_addButton = new GridBagConstraints();
		gbc_addButton.fill = GridBagConstraints.BOTH;
		gbc_addButton.insets = new Insets(0, 0, 0, 5);
		gbc_addButton.gridx = 6;
		gbc_addButton.gridy = 0;
		buttonPanel.add(addButton, gbc_addButton);

	}

	private void createClearScreenButton() {
		clearScreenButton = new JButton(new ImageIcon(classloader.getResource("images/clear.png")));
		clearScreenButton.setFocusable(false);
		clearScreenButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				textField.requestFocus();
				mainViewTextArea.setText("");
			}
		});
		GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
		gbc_btnNewButton.fill = GridBagConstraints.BOTH;
		gbc_btnNewButton.insets = new Insets(0, 0, 0, 5);
		gbc_btnNewButton.gridx = 4;
		gbc_btnNewButton.gridy = 0;
		buttonPanel.add(clearScreenButton, gbc_btnNewButton);
	}

	private void createDeleteButton() {
		deleteButton = new JButton(new ImageIcon(classloader.getResource("images/delete.png")));
		deleteButton.setFocusable(false);
		deleteButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (textField.getText().equals("")) {
					textField.requestFocus();
					textField.setText(DELETE + SPACE);
				} else {
					String text = DELETE + SPACE + textField.getText();
					Main.runCommands(text, mem);	
					textField.requestFocus();
					textField.setText("");
				}
			}
		});
		
		GridBagConstraints gbc_deleteButton = new GridBagConstraints();
		gbc_deleteButton.fill = GridBagConstraints.BOTH;
		gbc_deleteButton.gridx = 8;
		gbc_deleteButton.gridy = 0;
		buttonPanel.add(deleteButton, gbc_deleteButton);
	}

	private void createDisplayButton() {
		displayButton = new JButton(new ImageIcon(classloader.getResource("images/display.png")));
		displayButton.setFocusable(false);
		displayButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				Main.runCommands(DISPLAY, mem);
				textField.requestFocus();
			}
		});
		GridBagConstraints gbc_displayButton = new GridBagConstraints();
		gbc_displayButton.fill = GridBagConstraints.BOTH;
		gbc_displayButton.insets = new Insets(0, 0, 0, 5);
		gbc_displayButton.gridx = 2;
		gbc_displayButton.gridy = 0;
		buttonPanel.add(displayButton, gbc_displayButton);
	}

	private void createHelpButton() {
		helpButton = new JButton(new ImageIcon(classloader.getResource("images/help.png")));
		helpButton.setFocusable(false);
		helpButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				textField.requestFocus();
				mainViewTextArea.setText("");
				try {
					printWelcomeMessage();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
		GridBagConstraints gbc_helpButton = new GridBagConstraints();
		gbc_helpButton.fill = GridBagConstraints.BOTH;
		gbc_helpButton.insets = new Insets(0, 0, 0, 5);
		gbc_helpButton.gridx = 0;
		gbc_helpButton.gridy = 0;
		buttonPanel.add(helpButton, gbc_helpButton);
	}

	private void createMainUserInterfacePane() {
		bottomPanel = new JPanel();
		GridBagConstraints gbc_bottomPanel = new GridBagConstraints();
		gbc_bottomPanel.fill = GridBagConstraints.BOTH;
		gbc_bottomPanel.gridx = 0;
		gbc_bottomPanel.gridy = 1;
		frmSwing.getContentPane().add(bottomPanel, gbc_bottomPanel);
		GridBagLayout gbl_bottomPanel = new GridBagLayout();
		gbl_bottomPanel.columnWidths = new int[]{0, 490, 0};
		gbl_bottomPanel.rowHeights = new int[]{580, 0};
		gbl_bottomPanel.columnWeights = new double[]{1.0, 1.0, Double.MIN_VALUE};
		gbl_bottomPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		bottomPanel.setLayout(gbl_bottomPanel);
	}

	private void createViewAndTextPanel() {
		bottomRightPanel = new JPanel();
		GridBagConstraints gbc_bottomRightPanel = new GridBagConstraints();
		gbc_bottomRightPanel.fill = GridBagConstraints.BOTH;
		gbc_bottomRightPanel.gridx = 1;
		gbc_bottomRightPanel.gridy = 0;
		bottomPanel.add(bottomRightPanel, gbc_bottomRightPanel);
		GridBagLayout gbl_bottomRightPanel = new GridBagLayout();
		gbl_bottomRightPanel.columnWidths = new int[]{490, 0};
		gbl_bottomRightPanel.rowHeights = new int[]{580, 42, 0};
		gbl_bottomRightPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_bottomRightPanel.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE};
		bottomRightPanel.setLayout(gbl_bottomRightPanel);
	}

	private void createTextField() {
		textField = new JTextField();
		GridBagConstraints gbc_textField = new GridBagConstraints();
		gbc_textField.fill = GridBagConstraints.HORIZONTAL;
		gbc_textField.gridx = 0;
		gbc_textField.gridy = 1;
		bottomRightPanel.add(textField, gbc_textField);
		textField.addActionListener(this);
		textField.getDocument().addDocumentListener(this);
		textField.setColumns(10);
	}

	private void creatMainViewPane() {
		mainViewPanel = new JPanel();
		mainViewPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "<html><font size=+3 font face=Calibri Light>WELCOME TO SIMPLY</html>", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GridBagConstraints gbc_mainViewPanel = new GridBagConstraints();
		gbc_mainViewPanel.fill = GridBagConstraints.BOTH;
		gbc_mainViewPanel.insets = new Insets(0, 0, 5, 0);
		gbc_mainViewPanel.gridx = 0;
		gbc_mainViewPanel.gridy = 0;
		bottomRightPanel.add(mainViewPanel, gbc_mainViewPanel);
		GridBagLayout gbl_mainViewPanel = new GridBagLayout();
		gbl_mainViewPanel.columnWidths = new int[]{490, 0};
		gbl_mainViewPanel.rowHeights = new int[]{580, 0};
		gbl_mainViewPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_mainViewPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		mainViewPanel.setLayout(gbl_mainViewPanel);
		
		mainViewTextArea = new JTextArea();
		mainViewTextArea.setBorder(null);
		
		mainViewTextArea.setEditable(false);
		mainViewTextArea.setEditable(false);
		mainViewTextArea.setWrapStyleWord(true);	
		
		mainViewScrollPane = new JScrollPane(mainViewTextArea);
		mainViewScrollPane.setBorder(new CompoundBorder());
		GridBagConstraints gbc_mainViewScrollPane = new GridBagConstraints();
		gbc_mainViewScrollPane.fill = GridBagConstraints.BOTH;
		gbc_mainViewScrollPane.gridx = 0;
		gbc_mainViewScrollPane.gridy = 0;
		mainViewPanel.add(mainViewScrollPane, gbc_mainViewScrollPane);
		
		//change colour when in focus
		mainViewTextArea.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				mainViewTextArea.setBackground(Color.DARK_GRAY);
			}
			@Override
			public void focusLost(FocusEvent arg0) {
				mainViewTextArea.setBackground(null);
			}
		});
		
		//change font
		try {
			InputStream in = classloader.getResourceAsStream("SourceCodePro-Regular.ttf");
			Font ttfBase = Font.createFont(Font.TRUETYPE_FONT, in);
			Font ttfReal = ttfBase.deriveFont(Font.PLAIN, 13);
			mainViewTextArea.setFont(ttfReal);
		} catch (IOException | FontFormatException e) {
			e.printStackTrace();
		}
	}

	private void creatQuickViewPanel() {
		bottomLeftPanel = new JPanel();
		GridBagConstraints gbc_bottomLeftPanel = new GridBagConstraints();
		gbc_bottomLeftPanel.insets = new Insets(0, 0, 0, 5);
		gbc_bottomLeftPanel.fill = GridBagConstraints.BOTH;
		gbc_bottomLeftPanel.gridx = 0;
		gbc_bottomLeftPanel.gridy = 0;
		bottomPanel.add(bottomLeftPanel, gbc_bottomLeftPanel);
		GridBagLayout gbl_bottomLeftPanel = new GridBagLayout();
		gbl_bottomLeftPanel.columnWidths = new int[]{449, 0};
		gbl_bottomLeftPanel.rowHeights = new int[]{0, 0, 0, 0};
		gbl_bottomLeftPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_bottomLeftPanel.rowWeights = new double[]{1.0, 1.0, 1.0, Double.MIN_VALUE};
		bottomLeftPanel.setLayout(gbl_bottomLeftPanel);
	}

	private void createTaskPane() {
		taskPanel = new JPanel();
		taskPanel.setMinimumSize(new Dimension(6, 6));
		taskPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "<html><font size=+2>TASK</html>", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GridBagConstraints gbc_taskPanel = new GridBagConstraints();
		gbc_taskPanel.fill = GridBagConstraints.BOTH;
		gbc_taskPanel.gridx = 0;
		gbc_taskPanel.gridy = 2;
		bottomLeftPanel.add(taskPanel, gbc_taskPanel);
		GridBagLayout gbl_taskPanel = new GridBagLayout();
		gbl_taskPanel.columnWidths = new int[]{441, 0};
		gbl_taskPanel.rowHeights = new int[]{0, 0};
		gbl_taskPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_taskPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		taskPanel.setLayout(gbl_taskPanel);
		
		taskscrollPane = new JScrollPane();
		GridBagConstraints gbc_taskscrollPane = new GridBagConstraints();
		gbc_taskscrollPane.fill = GridBagConstraints.BOTH;
		gbc_taskscrollPane.gridx = 0;
		gbc_taskscrollPane.gridy = 0;
		taskPanel.add(taskscrollPane, gbc_taskscrollPane);
		
		taskTextPane = new JTextPane();
		taskTextPane.setBackground(null);
		
		//change color when in focus
		taskTextPane.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				taskTextPane.setBackground(Color.DARK_GRAY);
			}
			@Override
			public void focusLost(FocusEvent arg0) {
				taskTextPane.setBackground(null);
			}
		});
		taskscrollPane.setViewportView(taskTextPane);
		taskTextPane.setEditable(false);
	}

	private void createDeadlinePane() {
		deadlinePanel = new JPanel();
		deadlinePanel.setMinimumSize(new Dimension(6, 6));
		deadlinePanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "<html><font size=+2>DEADLINE</html>", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GridBagConstraints gbc_deadlinePanel = new GridBagConstraints();
		gbc_deadlinePanel.fill = GridBagConstraints.BOTH;
		gbc_deadlinePanel.insets = new Insets(0, 0, 5, 0);
		gbc_deadlinePanel.gridx = 0;
		gbc_deadlinePanel.gridy = 1;
		bottomLeftPanel.add(deadlinePanel, gbc_deadlinePanel);
		GridBagLayout gbl_deadlinePanel = new GridBagLayout();
		gbl_deadlinePanel.columnWidths = new int[]{131, 0};
		gbl_deadlinePanel.rowHeights = new int[]{0, 0};
		gbl_deadlinePanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_deadlinePanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		deadlinePanel.setLayout(gbl_deadlinePanel);
		
		deadlineScrollPane = new JScrollPane();
		GridBagConstraints gbc_deadlineScrollPane = new GridBagConstraints();
		gbc_deadlineScrollPane.fill = GridBagConstraints.BOTH;
		gbc_deadlineScrollPane.gridx = 0;
		gbc_deadlineScrollPane.gridy = 0;
		deadlinePanel.add(deadlineScrollPane, gbc_deadlineScrollPane);
		
		deadlineTextPane = new JTextPane();
		deadlineTextPane.setBackground(null);
		
		//change color when in focus
		deadlineTextPane.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				deadlineTextPane.setBackground(Color.DARK_GRAY);
			}
			@Override
			public void focusLost(FocusEvent arg0) {
				deadlineTextPane.setBackground(null);
			}
		});
		deadlineTextPane.setEditable(false);
		deadlineScrollPane.setViewportView(deadlineTextPane);
	}

	private void createEventPane() {
		eventPanel = new JPanel();
		eventPanel.setMinimumSize(new Dimension(6, 6));
		eventPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "<html><font size=+2>EVENT</html>", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GridBagConstraints gbc_eventPanel = new GridBagConstraints();
		gbc_eventPanel.fill = GridBagConstraints.BOTH;
		gbc_eventPanel.insets = new Insets(0, 0, 5, 0);
		gbc_eventPanel.gridx = 0;
		gbc_eventPanel.gridy = 0;
		bottomLeftPanel.add(eventPanel, gbc_eventPanel);
		GridBagLayout gbl_eventPanel = new GridBagLayout();
		gbl_eventPanel.columnWidths = new int[]{131, 0};
		gbl_eventPanel.rowHeights = new int[]{0, 0};
		gbl_eventPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE};
		gbl_eventPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE};
		eventPanel.setLayout(gbl_eventPanel);
		
		eventScrollPane = new JScrollPane();
		GridBagConstraints gbc_eventScrollPane = new GridBagConstraints();
		gbc_eventScrollPane.fill = GridBagConstraints.BOTH;
		gbc_eventScrollPane.gridx = 0;
		gbc_eventScrollPane.gridy = 0;
		eventPanel.add(eventScrollPane, gbc_eventScrollPane);
		
		eventTextPane = new JTextPane();
		eventTextPane.setBackground(null);
		eventTextPane.setEditable(false);
		eventScrollPane.setViewportView(eventTextPane);
		
		//change color when in focus
		eventTextPane.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent arg0) {
				eventTextPane.setBackground(Color.DARK_GRAY);
			}
			@Override
			public void focusLost(FocusEvent arg0) {
				eventTextPane.setBackground(null);
			}
		});
	}
		
	private void implementHotKeys() {
		bindHotKeys();
		
		bindScrollUpDown();
		
		bindScrollLeftRight();
	}

	private void bindScrollLeftRight() {
		int scrollableHorizontalIncrement = mainViewTextArea.getScrollableUnitIncrement(mainViewScrollPane.getVisibleRect(), 
                SwingConstants.HORIZONTAL, 1);
		
		mainViewTextArea.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
		mainViewTextArea.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
		mainViewTextArea.getActionMap().put(LEFT,new LeftRightAction(LEFT, mainViewScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		mainViewTextArea.getActionMap().put(RIGHT,new LeftRightAction(RIGHT, mainViewScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
	

		eventTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
		eventTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
		eventTextPane.getActionMap().put(LEFT,new LeftRightAction(LEFT, eventScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		eventTextPane.getActionMap().put(RIGHT,new LeftRightAction(RIGHT, eventScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		
		deadlineTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
		deadlineTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
		deadlineTextPane.getActionMap().put(LEFT,new LeftRightAction(LEFT, deadlineScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		deadlineTextPane.getActionMap().put(RIGHT,new LeftRightAction(RIGHT, deadlineScrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		
		taskTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
		taskTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
		taskTextPane.getActionMap().put(LEFT,new LeftRightAction(LEFT, taskscrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
		taskTextPane.getActionMap().put(RIGHT,new LeftRightAction(RIGHT, taskscrollPane.getHorizontalScrollBar().getModel(),scrollableHorizontalIncrement));
	}

	private void bindScrollUpDown() {
		int scrollableVerticalIncrement = mainViewTextArea.getScrollableUnitIncrement(mainViewScrollPane.getVisibleRect(), 
                SwingConstants.VERTICAL, 1);
		
		mainViewTextArea.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
		mainViewTextArea.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
		mainViewTextArea.getActionMap().put(UP,new UpDownAction(UP, mainViewScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		mainViewTextArea.getActionMap().put(DOWN,new UpDownAction(DOWN, mainViewScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		

		eventTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
		eventTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
		eventTextPane.getActionMap().put(UP,new UpDownAction(UP, eventScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		eventTextPane.getActionMap().put(DOWN,new UpDownAction(DOWN, eventScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		
		deadlineTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
		deadlineTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
		deadlineTextPane.getActionMap().put(UP,new UpDownAction(UP, deadlineScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		deadlineTextPane.getActionMap().put(DOWN,new UpDownAction(DOWN, deadlineScrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		
		taskTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
		taskTextPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
		taskTextPane.getActionMap().put(UP,new UpDownAction(UP, taskscrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
		taskTextPane.getActionMap().put(DOWN,new UpDownAction(DOWN, taskscrollPane.getVerticalScrollBar().getModel(),scrollableVerticalIncrement));
	}

	private void bindHotKeys() {
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(F1), HELP);
		textField.getActionMap().put(HELP,pressF1);
		
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(F2), DISPLAY);
		textField.getActionMap().put(DISPLAY,pressF2);
		
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(F3), CLEAR);
		textField.getActionMap().put(CLEAR,pressF3);
		
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(F4), ADD);
		textField.getActionMap().put(ADD,pressF4);
		
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(F5), DELETE);
		textField.getActionMap().put(DELETE,pressF5);
		
		textField.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(ESCAPE), EXIT);
		textField.getActionMap().put(EXIT,pressESCAPE);
	}
	
	// Action for our key binding to perform when bound event occurs
    private class UpDownAction extends AbstractAction {
        /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private BoundedRangeModel vScrollBarModel;
        private int scrollableIncrement;
        public UpDownAction(String name, BoundedRangeModel model, int scrollableIncrement) {
            super(name);
            this.vScrollBarModel = model;
            this.scrollableIncrement = scrollableIncrement;
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            String name = getValue(AbstractAction.NAME).toString();
            int value = vScrollBarModel.getValue();
            if (name.equals(UP)) {
                value -= scrollableIncrement;
                vScrollBarModel.setValue(value);
            } else if (name.equals(DOWN)) {
                value += scrollableIncrement;
                vScrollBarModel.setValue(value);
            }
        }
    }
    
    private class LeftRightAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		private BoundedRangeModel vScrollBarModel;
        private int scrollableIncrement;
        public LeftRightAction(String name, BoundedRangeModel model, int scrollableIncrement) {
            super(name);
            this.vScrollBarModel = model;
            this.scrollableIncrement = scrollableIncrement;
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            String name = getValue(AbstractAction.NAME).toString();
            int value = vScrollBarModel.getValue();
            if (name.equals(LEFT)) {
                value -= scrollableIncrement;
                vScrollBarModel.setValue(value);
            } else if (name.equals(RIGHT)) {
                value += scrollableIncrement;
                vScrollBarModel.setValue(value);
            }
        }
    }

	Action pressF1 = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
		mainViewTextArea.setText("");
			try {
				printWelcomeMessage();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	};
	
	Action pressF2 = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			Main.runCommands(DISPLAY, mem);
			mainViewTextArea.setCaretPosition(0);
		}
	};
	
	Action pressF3 = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			mainViewTextArea.setText("");
		}
	};
	
	Action pressF4 = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			
			if (textField.getText().equals("")) {
				textField.requestFocus();
				textField.setText(ADD + SPACE);
			} else {
				String text = ADD + SPACE + textField.getText();
				Main.runCommands(text, mem);	
				textField.setText("");
			}
		}
	};
	
	Action pressF5 = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (textField.getText().equals("")) {
				textField.requestFocus();
				textField.setText(DELETE + SPACE);
			} else {
				String text = DELETE + SPACE + textField.getText();
				Main.runCommands(text, mem);	
				textField.setText("");
			}
		}
	};
	
	Action pressESCAPE = new AbstractAction() {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			System.exit(0);
		}
	};

	private void setTextCursorInTextField() {
		//set text cursor in textField
	    SwingUtilities.invokeLater(new Runnable() {
	        public void run() {
	          textField.requestFocus();
	        }
	     });		
	}

	private void implementUndoRedoInTextField() {
		final UndoManager undo = new UndoManager();
		Document doc = textField.getDocument();
		
		// Listen for undo and redo events
		doc.addUndoableEditListener(new UndoableEditListener() {
			public void undoableEditHappened(UndoableEditEvent evt) {
		    undo.addEdit(evt.getEdit());
		    }
		  });
		
		// Create an undo action and add it to the text component
		textField.getActionMap().put(UNDO, new AbstractAction(UNDO) {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent evt) {
		    try {
		     if (undo.canUndo()) {
		      undo.undo();
		     }
		    } catch (CannotUndoException e) {
		    }
		   }
		  });

		  // Bind the undo action to ctl-Z
		textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), UNDO);

		  // Create a redo action and add it to the text component
		textField.getActionMap().put(REDO, new AbstractAction(REDO) {
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent evt) {
		    try {
		     if (undo.canRedo()) {
		      undo.redo();
		     }
		    } catch (CannotRedoException e) {
		    }
		   }
		  });

		  // Bind the redo action to ctl-Y
		  textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), REDO);	
	}

	// Listener methods
	@Override
	public void actionPerformed(ActionEvent e) {
	}
	
	@Override
	public void changedUpdate(DocumentEvent arg0) {
	}

	@Override
	public void removeUpdate(DocumentEvent arg0) {
	}
	
	@Override
    public void insertUpdate(DocumentEvent ev) {
        if (ev.getLength() != 1) {
            return;
        }
         
        int pos = ev.getOffset();
        String content = null;
        try {
            content = textField.getText(0, pos + 1);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
         
        // Find where the word starts
        int w;
        for (w = pos; w >= 0; w--) {
        	if (Character.isSpaceChar(content.charAt(w))) {
            	break;
            }
        }
        if (pos - w < 2) {
            // Too few chars
            return;
        }
         
        String prefix = content.substring(w + 1).toLowerCase();
        int n = Collections.binarySearch(words, prefix);
        if (n < 0 && -n <= words.size()) {
            String match = words.get(-n - 1);
            if (match.startsWith(prefix)) {
                // A completion is found
                String completion = match.substring(pos - w);
                // We cannot modify Document from within notification,
                // so we submit a task that does the change later
                SwingUtilities.invokeLater(new CompletionTask(completion, pos + 1));
            }
        } else {
            // Nothing found
            mode = Mode.INSERT;
        }
    }
     
    private class CompletionTask implements Runnable {
        String completion;
        int position;
         
        CompletionTask(String completion, int position) {
            this.completion = completion;
            this.position = position;
        }
               
        public void run() {
            StringBuffer sb = new StringBuffer(textField.getText());
            sb.insert(position, completion);
            textField.setText(sb.toString());
            textField.setCaretPosition(position + completion.length());
            textField.moveCaretPosition(position);
            mode = Mode.COMPLETION;
          }
    }
     
    private class CommitAction extends AbstractAction {
    	
		private static final long serialVersionUID = 1L;

		@Override
        public void actionPerformed(ActionEvent ev) {
          if (mode == Mode.COMPLETION) {
            int pos = textField.getSelectionEnd();
            StringBuffer sb = new StringBuffer(textField.getText());
            sb.insert(pos, SPACE);
            textField.setText(sb.toString());
            textField.setCaretPosition(pos + 1);
            mode = Mode.INSERT;
          } else {
        	  String text = textField.getText();
        	  
        	  //reset textField
        	  textField.selectAll();
              textField.setText("");
        	  
              
             Main.runCommands(text, mem);

              //Make sure the new text is visible, even if there was a selection in the text area.
              mainViewTextArea.setCaretPosition(mainViewTextArea.getDocument().getLength());
          }
        }
    }
    
    public static void updateQuickView() {
		Mark.refreshMark(mem,0);
    	eventTextPane.setText("");
    	deadlineTextPane.setText("");
    	taskTextPane.setText("");

		for(int i = 0; i < mem.getSize(); i++) {
			String type = mem.memory.get(i).getType();
			String name = mem.memory.get(i).getName();
			int state = mem.memory.get(i).getState();
			
			if(state!=1) {
				switch(type) {
				case TASK: 
					try {
						taskStyledDoc.insertString(taskStyledDoc.getLength(),name,eventStyledDoc.getStyle(LARGE));
						taskStyledDoc.insertString(taskStyledDoc.getLength(),newline,null);
						taskTextPane.setCaretPosition(0);
					} catch (BadLocationException e1) {
						e1.printStackTrace();
					}
					
					break;
					
				case DEADLINE:
					if(state == 2) { //overdue
						try {
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),name,eventStyledDoc.getStyle(REDLARGE));
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),OPENBRACKETWITHSPACE + GenericEvents.getDate(GuiMain.mem.memory.get(i).getEnd()) + SPACE + GenericEvents.getTime(GuiMain.mem.memory.get(i).getEnd()) + CLOSEBRACKET,eventStyledDoc.getStyle(RED));
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),newline,null);	
							deadlineTextPane.setCaretPosition(0);
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					} else {
						try {
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),name,eventStyledDoc.getStyle(LARGE));
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),OPENBRACKETWITHSPACE + GenericEvents.getDate(GuiMain.mem.memory.get(i).getEnd()) + SPACE + GenericEvents.getTime(GuiMain.mem.memory.get(i).getEnd()) + CLOSEBRACKET,null);
							deadlineStyledDoc.insertString(deadlineStyledDoc.getLength(),newline,null);	
							deadlineTextPane.setCaretPosition(0);
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					}
					
					
	
					break;
					
				case EVENT:
					if(state == 2) { //ongoing
						try {
							eventStyledDoc.insertString(eventStyledDoc.getLength(),name,eventStyledDoc.getStyle(GREENLARGE));
							eventStyledDoc.insertString(eventStyledDoc.getLength(),OPENBRACKETWITHSPACE + GenericEvents.getDate(GuiMain.mem.memory.get(i).getStart()) + DASH + GenericEvents.getDate(GuiMain.mem.memory.get(i).getEnd())+ CLOSEBRACKET,eventStyledDoc.getStyle(GREEN));
							eventStyledDoc.insertString(eventStyledDoc.getLength(),newline,null);	
							eventTextPane.setCaretPosition(0);
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					} else {
						try {
							eventStyledDoc.insertString(eventStyledDoc.getLength(),name,eventStyledDoc.getStyle(LARGE));
							eventStyledDoc.insertString(eventStyledDoc.getLength(),OPENBRACKETWITHSPACE + GenericEvents.getDate(GuiMain.mem.memory.get(i).getStart()) + DASH + GenericEvents.getDate(GuiMain.mem.memory.get(i).getEnd())+ CLOSEBRACKET,null);
							eventStyledDoc.insertString(eventStyledDoc.getLength(),newline,null);	
							eventTextPane.setCaretPosition(0);
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					}
	
					break;
					
				default:
					break;
				}
			}		
		}
		
	}
}
